pub mod cp_numeric;
pub mod cp_utf8;
pub mod cp_string;
pub mod cp_class;
pub mod cp_name_and_type;
pub mod cp_member_ref;
pub mod cp_invoke_dynamic;

use std::rc::Rc;
use std::cell::RefCell;

use cp_class::ConstantClassInfo;
pub use cp_invoke_dynamic::*;
use cp_member_ref::{ConstantFieldrefInfo, ConstatnInterfaceMethodrefInfo, ConstantMethodrefInfo};
use cp_name_and_type::ConstantNameAndTypeInfo;
use cp_string::ConstantStringInfo;
use cp_utf8::ConstantUtf8Info;
use super::{ClassReader, ConstantPool};
use cp_numeric::{ConstantIntegerInfo, ConstantFloatInfo, ConstantLongInfo, ConstantDoubleInfo};


// 常量池的项目类型
pub const CONSTANT_UTF8               : usize = 1;  // UTF-8编码的字符串
pub const CONSTANT_INTEGER            : usize = 3;  // 整形字面量
pub const CONSTANT_FLOAT              : usize = 4;  // 浮点型字面量
pub const CONSTANT_LONG               : usize = 5;  // 长整型字面量
pub const CONSTANT_DOUBLE             : usize = 6;  // 双精度浮点型字面量
pub const CONSTANT_CLASS              : usize = 7;  // 类或接口的符号引用
pub const CONSTANT_STRING             : usize = 8;  // 字符串类型字面量
pub const CONSTANT_FIELDREF           : usize = 9;  // 字段的符号引用
pub const CONSTANT_METHODREF          : usize = 10; // 类中方法的符号引用
pub const CONSTANT_INTERFACE_METHODREF: usize = 11; // 接口中方法的符号引用
pub const CONSTANT_NAME_AND_TYPE      : usize = 12; // 字段或方法的部分符号引用
pub const CONSTANT_METHOD_HANDLE      : usize = 15; // 表示方法句柄
pub const CONSTANT_METHOD_TYPE        : usize = 16; // 表示方法类型
// pub const CONSTANT_DYNAMIC            : usize = 17; // 表示一个动态计算常量
pub const CONSTANT_INVOKE_DYNAMIC     : usize = 18; // 表示一个动态方法调用点
// pub const CONSTANT_MODULE             : usize = 19; // 表示一个模块
// pub const CONSTANT_PACKAGE            : usize = 18; // 表示一个模块中开放或导出的包

/*
cp_info {
    u1 tag;
    u1 info[];
}
*/
pub trait ConstantInfo {
    fn read_info(&mut self, reader: &mut ClassReader);

    // // CONSTANT_LONG和CONSTANT_DOUBLE需要占两个位置，此方法判断
    // fn long_or_double(&self) -> bool { false }

    // // 将dyn ConstantInfo转为具体类型用dyn Any实现
    // fn as_any(&self) -> &dyn Any;
}

// 读取一个常量
pub fn read_constant_info(reader: &mut ClassReader, cp: Rc<RefCell<ConstantPool>>) -> ConstantType {
    let tag = reader.read_u8().into();
    let mut c = new_constant_info(tag, cp.clone());
    c.read_info(reader);
    c
}

// 根据标识创建类型
pub fn new_constant_info(tag: usize, cp: Rc<RefCell<ConstantPool>>) -> ConstantType {
    match tag {
        CONSTANT_UTF8                => ConstantType::ConstantUtf8(ConstantUtf8Info::new()),
        CONSTANT_INTEGER             => ConstantType::ConstantInteger(ConstantIntegerInfo::new()),
        CONSTANT_FLOAT               => ConstantType::ConstantFloat(ConstantFloatInfo::new()),
        CONSTANT_LONG                => ConstantType::ConstantLong(ConstantLongInfo::new()),
        CONSTANT_DOUBLE              => ConstantType::ConstantDouble(ConstantDoubleInfo::new()),
        CONSTANT_CLASS               => ConstantType::ConstantClass(ConstantClassInfo::new(cp)),
        CONSTANT_STRING              => ConstantType::ConstantString(ConstantStringInfo::new(cp)),
        CONSTANT_FIELDREF            => ConstantType::ConstantFieldref(ConstantFieldrefInfo::new(cp)),
        CONSTANT_METHODREF           => ConstantType::ConstantMethodref(ConstantMethodrefInfo::new(cp)),
        CONSTANT_INTERFACE_METHODREF => ConstantType::ConstantInterfaceMethodref(ConstatnInterfaceMethodrefInfo::new(cp)),
        CONSTANT_NAME_AND_TYPE       => ConstantType::ConstantNameAndType(ConstantNameAndTypeInfo::new()),
        CONSTANT_METHOD_HANDLE       => ConstantType::ConstantMethodHandle(ConstantMethodHandleInfo::new(cp)),
        CONSTANT_METHOD_TYPE         => ConstantType::ConstantMethodType(ConstantMethodTypeInfo::new(cp)),
        CONSTANT_INVOKE_DYNAMIC      => ConstantType::ConstantInvokeDynamic(ConstantInvokeDynamicInfo::new(cp)),
        _ => panic!("java.lang.ClassFormatError: constant poll tag!")
    }

}

// 定义枚举，已完成类型匹配
pub enum ConstantType {
    ConstantUtf8(ConstantUtf8Info),
    ConstantInteger(ConstantIntegerInfo),
    ConstantFloat(ConstantFloatInfo),
    ConstantLong(ConstantLongInfo),
    ConstantDouble(ConstantDoubleInfo),
    ConstantClass(ConstantClassInfo),
    ConstantString(ConstantStringInfo),
    ConstantFieldref(ConstantFieldrefInfo),
    ConstantMethodref(ConstantMethodrefInfo),
    ConstantInterfaceMethodref(ConstatnInterfaceMethodrefInfo),
    ConstantNameAndType(ConstantNameAndTypeInfo),
    ConstantMethodHandle(ConstantMethodHandleInfo),
    ConstantMethodType(ConstantMethodTypeInfo),
    ConstantInvokeDynamic(ConstantInvokeDynamicInfo)
}

impl ConstantInfo for ConstantType {
    fn read_info(&mut self, reader: &mut ClassReader) {
        match self {
            Self::ConstantUtf8(constant) => constant.read_info(reader),
            Self::ConstantInteger(constant) => constant.read_info(reader),
            Self::ConstantFloat(constant) => constant.read_info(reader),
            Self::ConstantLong(constant) => constant.read_info(reader),
            Self::ConstantDouble(constant) => constant.read_info(reader),
            Self::ConstantClass(constant) => constant.read_info(reader),
            Self::ConstantString(constant) => constant.read_info(reader),
            Self::ConstantFieldref(constant) => constant.read_info(reader),
            Self::ConstantMethodref(constant) => constant.read_info(reader),
            Self::ConstantInterfaceMethodref(constant) => constant.read_info(reader),
            Self::ConstantNameAndType(constant) => constant.read_info(reader),
            Self::ConstantMethodHandle(constant) => constant.read_info(reader),
            Self::ConstantMethodType(constant) => constant.read_info(reader),
            Self::ConstantInvokeDynamic(constant) => constant.read_info(reader),
        }
    }
}

impl ConstantType {
    pub fn long_or_double(&self) -> bool {
        match self {
            Self::ConstantLong(_) | Self::ConstantDouble(_) => true,
            _ => false
        }
    }
}
